package com.northpool.operator.http.covert;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.JAXBUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.northpool.operator.annotation.InputParam;
import com.northpool.operator.annotation.InputParams;
import com.northpool.operator.annotation.OperatorInfo;
import com.northpool.operator.common.algorithm.OperatorTestBuild;
import com.northpool.operator.common.algorithm.TestParamBuilder;
import com.northpool.operator.common.minio.MinIOUtil;
import com.northpool.operator.common.util.XmlParser;
import com.northpool.operator.http.bean.AppMetadata;
import com.northpool.operator.http.bean.HttpOperatorBean;
import com.northpool.operator.param.ParamTool;
import com.northpool.operator.type.TypeEnum;
import com.northpool.operator.utils.StpOperatorHelper;
import io.minio.Result;
import io.minio.messages.Item;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.LinkedList;

@OperatorInfo(
        ref = "BuildAppMetaOperator",
        name = "HTTP应用元数据信息生成",
        description = "扫描对象存储中版本库的HTTP算子文件，生成应用元数据信息"
)
public class BuildAppMetaOperator extends StpOperatorHelper {

    @InputParams({
            @InputParam(ref = "path", name = "minio中对象路径", desc = "minio中对象路径, 如: apps/supermap/",  type = TypeEnum.STRING),
            @InputParam(ref = "docReg", name = "文档文件匹配规则", desc = "文档文件名的正则表达式, 如: .*.pdf$", value = ".*.pdf$",  type = TypeEnum.STRING),
            @InputParam(ref = "refresh", name = "刷新元数据文件", desc = "是否刷新元数据文件 STP_META.xml, 如: false", value = "false",  type = TypeEnum.BOOL),
            @InputParam(ref = "minioEndpoint", name = "对象存储地址", desc = "http://ip:port", type = TypeEnum.STRING),
            @InputParam(ref = "bucket", name = "桶名称", desc = "桶名称, 如: stp-minio", type = TypeEnum.STRING),
            @InputParam(ref = "accessKey", name = "minio令牌", desc = "minio令牌, 如: northpool", type = TypeEnum.STRING),
            @InputParam(ref = "secretKey", name = "minio密钥", desc = "minio密钥, 如: xxxxxxx", type = TypeEnum.STRING)
    })
    public BuildAppMetaOperator() {
    }

    public static void main(String[] args) throws Exception {
        OperatorTestBuild.execute(BuildAppMetaOperator.class, TestParamBuilder.aBuilder()
                .param("path", "apps/supermap/")
                .param("minioEndpoint", "http://northpool.work:9000")
//                .param("minioEndpoint", "http://192.168.164.45:9000")
                .param("refresh", "true")
                .param("bucket", "stp-minio")
                .param("accessKey", "northpool")
                .param("secretKey", "piesat@123")
                .param("docReg", ".*.pdf$")
                .build());
    }

    static String appRe = "";
    static String docRe = "";
    static boolean refresh = false;

    @Override
    public void execute(ParamTool paramTool) throws Exception {
        String bucket = paramTool.getStr("bucket");
        String path = paramTool.getStr("path");
        String minioEndpoint = paramTool.getStr("minioEndpoint");
        String accessKey = paramTool.getStr("accessKey");
        String secretKey = paramTool.getStr("secretKey");
        appRe = paramTool.getStr("appReg");
        docRe = paramTool.getStr("docReg");
        refresh = paramTool.getBool("refresh");

        MinIOUtil minioUtil = new MinIOUtil(minioEndpoint, accessKey, secretKey);
        try {
            processDirItem(minioUtil, bucket, path);
        } catch (Exception ex) {
            error("处理失败: {}",ex.getMessage());
            failedExit();
        }
    }

    private void processDirItem(MinIOUtil minioUtil, String bucket, String path) throws Exception {
        Iterable<Result<Item>> results = minioUtil.listObjects(bucket, path);
        for (Result<Item> result : results) {
            Item item = result.get();
            boolean dir = item.isDir();
            if (dir) {
                processDirItem(minioUtil, bucket, item.objectName());
            } else {
                String objectName = item.objectName();
                // 跳过隐藏文件
                int index = objectName.lastIndexOf("/");
                String fileName = objectName.substring(index + 1);
                if (fileName.startsWith(".")) {
                    continue;
                }

                boolean exists = minioUtil.objectExists(bucket, path + "STP_META.xml");
                // 没有元数据信息的时候才处理
                if (!exists || refresh) {
                    try {
                        boolean flag = processFileItem(minioUtil, bucket, path, objectName);
                        if (flag) {
                            break;
                        }
                    } catch (Exception ex) {
                        this.error("STP_META处理失败：" + objectName);
                        this.error(ex.getMessage());
                    }
                }
            }
        }
    }

    private boolean processFileItem(MinIOUtil minioUtil, String bucket, String parentPath, String objectName) throws Exception {
        if (!objectName.endsWith(".xml") || objectName.endsWith("/STP_META.xml")) {
            return false;
        }
        InputStream inputStream = minioUtil.getObject(bucket, objectName);
        String xmlString = IoUtil.readUtf8(inputStream);
        HttpOperatorBean opBean = JAXBUtil.xmlToBean(xmlString, HttpOperatorBean.class);

        AppMetadata appMetadata = new AppMetadata();
        appMetadata.setName(opBean.getName());
        appMetadata.setDescription(opBean.getDescription());
        String version = StrUtil.isBlank(opBean.getVersion()) ? "1.0.0" : opBean.getVersion().trim();
        String packageName = StrUtil.subAfter(objectName, "/", true);

        // 查找是否有pdf文档
        String docFileName = "";
        Iterable<Result<Item>> results = minioUtil.listObjects(bucket, parentPath);
        for (Result<Item> result : results) {
            Item item = result.get();
            String fileName = StrUtil.subAfter(item.objectName(), "/", true);
            if (item.objectName().endsWith("/" + objectName)) {
                continue;
            }
            if (ReUtil.isMatch(docRe, fileName)) {
                docFileName = fileName;
                break;
            }
        }

        appMetadata.setVersion(version);
        appMetadata.setReleaseDate(DateUtil.formatDate(new Date()));
        appMetadata.setDocumentFile(docFileName);
        appMetadata.setPackageFile(packageName);
        appMetadata.setUpdateFeatures(new LinkedList<>());

        String metaStr = XmlParser.convertToXml(appMetadata);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(metaStr.getBytes(StandardCharsets.UTF_8));
        minioUtil.putObject(bucket, parentPath + "STP_META.xml", byteArrayInputStream, "text/xml; charset=utf-8");
        this.log("处理完成：" + objectName);
        return true;
    }

}
